package net.lulihu.pangolin.headless.server.handler;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import lombok.extern.slf4j.Slf4j;
import net.lulihu.pangolin.headless.common.container.annotation.Component;
import net.lulihu.pangolin.headless.common.protocol.ProtocolMessage;
import net.lulihu.pangolin.headless.common.protocol.ProtocolMessageType;
import net.lulihu.pangolin.headless.common.protocol.handler.RegistrationMessageTypeHandlerComponent;
import net.lulihu.pangolin.headless.common.util.ChannelTwoWayBindKit;
import net.lulihu.pangolin.headless.server.kit.ServerWaitBindChannelKit;

/**
 * 真实服务器地址连接结果消息处理程序
 */
@Slf4j
@Component
public class RealServerAddressConnectResultMessageHandler implements RegistrationMessageTypeHandlerComponent {

    @Override
    public byte[] messageTypes() {
        return new byte[]{
                ProtocolMessageType.C_TWO_WAY_CHANNEL_CONNECT_SETUP,
                ProtocolMessageType.C_REAL_CHANNEL_CONNECT_FAIL,
                ProtocolMessageType.C_DEDICATED_AGENT_CHANNEL_CONNECT_FAIL
        };
    }

    @Override
    public void handle(ChannelHandlerContext context, ProtocolMessage message) {
        switch (message.getType()) {
            case ProtocolMessageType.C_TWO_WAY_CHANNEL_CONNECT_SETUP:
                twoWayChannelConnectSetup(context, message);
                break;
            case ProtocolMessageType.C_REAL_CHANNEL_CONNECT_FAIL:
                realChannelConnectFail(context, message);
                break;
            case ProtocolMessageType.C_DEDICATED_AGENT_CHANNEL_CONNECT_FAIL:
                dedicatedAgentChannelConnectFail(context, message);
                break;
            default:
                log.error("未定义的消息处理类型...");
                break;

        }
    }

    /**
     * 双向通道连接成功消息
     */
    private void twoWayChannelConnectSetup(ChannelHandlerContext context, ProtocolMessage message) {
        if (log.isDebugEnabled()) log.debug("收到客户端双向通道连接成功消息");

        Channel proxyChannel = context.channel();
        String channelId = message.getBodyStr();

        Channel userChannel = ServerWaitBindChannelKit.bindChannelAndReturn(channelId, proxyChannel);
        // 用户通道绑定丢失 告诉客户端关闭连接
        if (userChannel == null) {
            ProtocolMessage lostBinding = new ProtocolMessage();
            lostBinding.setType(ProtocolMessageType.S_USER_CHANNEL_LOST_BINDING);
            proxyChannel.writeAndFlush(lostBinding);
            proxyChannel.close();
            return;
        }

        // 设置为可读
        userChannel.config().setOption(ChannelOption.AUTO_READ, true);
    }

    /**
     * 与真实服务连接失败
     */
    private void realChannelConnectFail(ChannelHandlerContext context, ProtocolMessage message) {
        if (log.isDebugEnabled()) log.debug("收到客户端与真实服务连接失败消息");
        connectFail(context, message);
    }

    /**
     * 专用代理通道连接失败
     */
    private void dedicatedAgentChannelConnectFail(ChannelHandlerContext context, ProtocolMessage message) {
        if (log.isDebugEnabled()) log.debug("收到客户端为真实服务开辟专用代理通道连接失败消息");
        connectFail(context, message);
    }

    private void connectFail(ChannelHandlerContext context, ProtocolMessage message) {
        Channel userChannel = ServerWaitBindChannelKit.takeWaitBindChannel(message.getBodyStr());
        if (userChannel != null) {
            ChannelTwoWayBindKit.unbind(userChannel);
            userChannel.close();
        }
    }

}
